package cc.rengu.igas.smps.core.packswitch;

import cc.rengu.igas.smps.common.enums.RespCodeEnum;
import cc.rengu.jradp.packetswitch.IncomingPackSwitchImpl;
import cc.rengu.jradp.packetswitch.OutgoingPackSwitchImpl;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.realize.HsmService;
import cc.rengu.oltp.service.realize.impl.HsmServiceImpl;
import cc.rengu.oltp.utility.util.StringUtil;
import cc.rengu.oltp.utility.util.XmlTreeUtil;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.ByteArrayInputStream;
import java.util.Iterator;

/**
 * 与ESB通讯层报文解包前后、组前包后实现类
 */
public class SmpsEsbPackSwitch implements IncomingPackSwitchImpl, OutgoingPackSwitchImpl {
    private RgLogger rglog = RgLog.getLogger(this.getClass().getName());

    @Override
    public byte[] beforeInComPackSwitch(byte[] bytes) {
        rglog.debug("beforeInComPackSwitch");
        return bytes;
    }

    @Override
    public int afterInComPackSwitch() {
        rglog.debug("afterInComPackSwitch");
        return 0;
    }

    @Override
    public int beforeOutgoPackSwitch() {
        rglog.debug("beforeOutgoPackSwitch");

        return 0;
    }

    @Override
    public byte[] afterOutgoPackSwitch(byte[] bytes) throws Exception {
        rglog.debug("afterOutgoPackSwitch");
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String txnNum = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.TXN_NUM);
        if ("00410000000002".equals(txnNum)) {
            return bytes;
        }
        String xmlBefore = new String(bytes);
        /* 生成生成数字签名的字符串 */
        String signBlockString = generateSignBlockString(xmlBefore);
        rglog.info("加签Block:{}", signBlockString);
        //signBlockString 换取MAC
        String mac = "";
        try {
            String instId = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.INST_ID);
            HsmService hsmService = new HsmServiceImpl();
            mac = hsmService.hsmGenerateMac(instId, "", signBlockString);
        } catch (Throwable throwable) {
            rglog.error("error = <{}>", throwable.getMessage());
            throw new BizException(RespCodeEnum.GENERATE_SIGN_BLOCK_ERROR.getRespCode(), RespCodeEnum.GENERATE_SIGN_BLOCK_ERROR.getRespDesc());
        }
        rglog.debug("mac = <{}>", mac);
        //将MAC值赋值到/Service/Service_Body/MAC中
        String xmlAfter = setMacToReq(xmlBefore, mac);
        rglog.debug("xmlAfter = <{}>", xmlAfter);
        return xmlAfter.getBytes();
    }

    private String setMacToReq(String xmlBefore, String mac) throws DocumentException {

        SAXReader reader = new SAXReader();
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(xmlBefore.getBytes());
        Document document = reader.read(byteArrayInputStream);
        Element rootElement = document.getRootElement();
        rglog.debug("根节点名称 = <{}>", rootElement.getName());//根节点Service
        Element serviceBodyNode = rootElement.element("Service_Body");

        Element macNode = serviceBodyNode.addElement("MAC");
        macNode.setText(mac);
        rglog.debug("after document = <{}>", document.asXML());
        return document.asXML();
    }

    private String generateSignBlockString(String xmlBefore) throws DocumentException {
        rglog.debug("generateSignBlockString--xmlBefore = <{}>", xmlBefore);
        String signBlock;
        SAXReader reader = new SAXReader();
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(xmlBefore.getBytes());
        Document document = reader.read(byteArrayInputStream);

        Element rootElement = document.getRootElement();
        rglog.debug("根节点名称 = <{}>", rootElement.getName());//根节点Service

        //获取指定节点 /Service/Service_Header/service_sn   /Service/Service_Header/service_time  获取加签值 serviceSnVal和serviceTimeVal
        Element serviceSnNode = rootElement.element("Service_Header").element("service_sn");
        String serviceSnVal = serviceSnNode.getText();
        rglog.debug("serviceSnVal = <{}>", serviceSnVal);
        Element serviceTimeNode = rootElement.element("Service_Header").element("service_time");
        String serviceTimeVal = serviceTimeNode.getText();
        rglog.debug("serviceTimeVal = <{}>", serviceTimeVal);
        //需要遍历的子节点 /Service/Service_Body/request
        Element requestNode = rootElement.element("Service_Body").element("request");
        //递归遍历该节点下的所有子节点
        String requestSignBlock = getChildNodeValue(requestNode);
        rglog.debug("requestSignBlock = <{}>", requestSignBlock);


        signBlock = serviceSnVal + serviceTimeVal + requestSignBlock;
        rglog.debug("signBlock = <{}>", signBlock);
        if (signBlock.length() > 512) {
            signBlock = signBlock.substring(0, 512);
            rglog.debug("signBlock = <{}>", signBlock);
        }
        return signBlock;
    }

    private String getChildNodeValue(Element requestNode) {
        rglog.debug("requestNodeName = <{}>", requestNode.getName());
        Iterator<Node> iterator = requestNode.nodeIterator();
        StringBuilder stringBuilder = new StringBuilder();
        while (iterator.hasNext()) {
            Node node = iterator.next();
            if (node instanceof Element) {
                Element paramNode = (Element) node;
                rglog.debug("paramNode = <{}>", paramNode.getName());
                String subParamNode = getChildNodeValue(paramNode);
                if (StringUtil.isEmptyOrNull(subParamNode)) {
                    rglog.debug("该节点不存在子节点，paramNode = <{}>", paramNode.getName());
                    stringBuilder.append(StringUtil.filterAsciiString(paramNode.getText()));
                    rglog.debug("stringBuilder = <{}>", stringBuilder);
                } else {
                    rglog.debug("subParamNode is not null ,continue");
                    String subStr = getChildNodeValue(paramNode);
                    stringBuilder.append(StringUtil.filterAsciiString(subStr));
                }
            }
        }
        return stringBuilder.toString();
    }

}
